#include "net_io_loop.hh"
#include "network_selector.hh"
#include "../logger/writer.hh"
#include "../object_pool.hpp"

using namespace kratos::corelib;

namespace kratos {
namespace network {

NetIoLoop::NetIoLoop() {
    REGISTER_EVENT_MEMBER_HANDLER(NetEventWorkerType::MainToWorkerNewAcceptor, NetIoLoop::onMainToWorkerNewAcceptor_);
    REGISTER_EVENT_MEMBER_HANDLER(NetEventWorkerType::MainToWorkerNewConnector, NetIoLoop::onMainToWorkerNewConnector_);
    REGISTER_EVENT_MEMBER_HANDLER(NetEventWorkerType::MainToWorkerSend, NetIoLoop::onMainToWorkerSend_);
    REGISTER_EVENT_MEMBER_HANDLER(NetEventWorkerType::MainToWorkerClose, NetIoLoop::onMainToWorkerClose_);
}

void NetIoLoop::start(NetworkSelector * loop) {
    loop_ = loop;
}

NetworkSelector * NetIoLoop::getLoop() {
    return loop_;
}

std::uint64_t NetIoLoop::onNewAcceptor(const std::string & ip, const uint16_t port,
    std::size_t netBufSize) {
    throw std::runtime_error("NetIOLoop::onNewAcceptor need implement");
}

std::uint64_t NetIoLoop::onNewConnector(const std::string & ip, const uint16_t port,
    std::size_t netBufSize) {
    throw std::runtime_error("NetIOLoop::onNewConnector need implement");
}

void NetIoLoop::onClose(std::uint64_t channelID) {
    throw std::runtime_error("NetIOLoop::onClose need implement");
}

void NetIoLoop::onSend(std::uint64_t channelID, const char * data, std::uint32_t size) {
    throw std::runtime_error("NetIOLoop::onSend need implement");
}

void NetIoLoop::onMainToWorkerNewAcceptor_(Event * event) {
    auto newAcceptorTCP = dynamic_cast<NetEventWorker*>(event);
    if (!newAcceptorTCP) {
        return;
    }
    auto channelID = onNewAcceptor(newAcceptorTCP->ip(), newAcceptorTCP->port(),
        newAcceptorTCP->getNetBufSize());
    auto bindTCP = allocate<NetEventMain>(
        static_cast<std::uint32_t>(EventID::EventID_MainBind),
        NetEventMainType::WorkerToMainBinded);
    bindTCP->setChannel(channelID);
    loop_->notifyMain(bindTCP);
}

void NetIoLoop::onMainToWorkerNewConnector_(Event * event) {
    auto newConnectorTCP = dynamic_cast<NetEventWorker*>(event);
    if (!newConnectorTCP) {
        return;
    }
    onNewConnector(newConnectorTCP->ip(), newConnectorTCP->port(), newConnectorTCP->getNetBufSize());
}

void NetIoLoop::onMainToWorkerClose_(Event * event) {
    auto closeTCP = dynamic_cast<NetEventWorker*>(event);
    if (!closeTCP) {
        return;
    }
    onClose(closeTCP->channel());
}

void NetIoLoop::onMainToWorkerSend_(Event * event) {
    auto sendTCP = dynamic_cast<NetEventWorker*>(event);
    if (!sendTCP) {
        return;
    }
    onSend(sendTCP->channel(), sendTCP->data(), sendTCP->size());
}

void NetIoLoop::onAccepted(std::uint64_t channelID) {
    auto acceptedTCP = allocate<NetEventMain>(
        static_cast<std::uint32_t>(EventID::EventID_MainAccepted),
            NetEventMainType::WorkerToMainAccepted);
    acceptedTCP->setChannel(channelID);
    loop_->notifyMain(acceptedTCP);
}

void NetIoLoop::onConnected(std::uint64_t channelID) {
    auto connectedTCP = allocate<NetEventMain>(
        static_cast<std::uint32_t>(EventID::EventID_MainConnected),
            NetEventMainType::WorkerToMainConnected);
    connectedTCP->setChannel(channelID);
    loop_->notifyMain(connectedTCP);
}

void NetIoLoop::onClosed(std::uint64_t channelID) {
    auto mainCloseTCP = allocate<NetEventMain>(
        static_cast<std::uint32_t>(EventID::EventID_MainClose),
            NetEventMainType::WorkerToMainClose);
    mainCloseTCP->setChannel(channelID);
    loop_->notifyMain(mainCloseTCP);
}

void NetIoLoop::onReceived(std::uint64_t channelID, const char * data, std::uint32_t size) {
    auto receiveTCP = allocate<NetEventMain>(
        static_cast<std::uint32_t>(EventID::EventID_MainRecv),
            NetEventMainType::WorkerToMainRecv);
    receiveTCP->setData(data, size);
    receiveTCP->setChannel(channelID);
    loop_->notifyMain(receiveTCP);
}

}
}

